﻿<!DOCTYPE html>
<html>
<head>
	<title>ol-ext: Convex hull</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

	<meta name="description" content="Calculate the convex hull of the cluster to show its envelope." />
	<meta name="keywords" content="ol3, ckuster, polygon, convex hull, envelope" />

	<!-- jQuery -->
	<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>

	<!-- Openlayers -->
    <link rel="stylesheet" href="https://openlayers.org/en/latest/css/ol.css" />
	<script type="text/javascript" src="https://openlayers.org/en/latest/build/ol.js"></script>
	<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL,Object.assign"></script>
	
	<!-- ol-ext -->
    <link rel="stylesheet" href="../../dist/ol-ext.css" />
	<script type="text/javascript" src="../../dist/ol-ext.js"></script>

	<link rel="stylesheet" href="../style.css" />
</head>
<body >
	<a href="https://github.com/Viglino/ol-ext" class="icss-github-corner"><i></i></a>

	<a href="../../index.html">
		<h1>ol-ext: Convex hull</h1>
	</a>
	<div class="info">
		This example uses a <i>ol.coordinate.convexHull()</i> function to calculate a <a href="https://en.wikipedia.org/wiki/Convex_hull">convex hull</a>
		or convex envelope to display a polygon around the points of a cluster.
		<br /><br />
		<ul>
			<li>
				Look at <a href="../animation/map.animatedcluster.html">AnimatedCluster</a> for more example on clusters.
			</li>
			<li>
				Look at the <a href="map.convexhull.html">convex hull example</a> for more information on the envelope calculation.
			</li>
		</ul>
	</div>

	<!-- Map div -->
	<div id="map" style="width:600px; height:400px;"></div>
	
	<div class="options">
		Move over the features to see the convex hull of the cluster.
	</div>

	<script type="text/javascript">

	// Two base layers
	var stamen = new ol.layer.Tile(
		{	title: "Watercolor",
			baseLayer: true,
			source: new ol.source.Stamen({
				layer: 'watercolor'
			})
		});

	// The map
	var map = new ol.Map
		({	target: 'map',
			view: new ol.View
			({	zoom: 4,
				center: [205461, 5867916]
			}),
			layers: [stamen]
		});

	// Style for the clusters
	var styleCache = {};
	function getStyle (feature, resolution)
	{	var size = feature.get('features').length;
		var style = styleCache[size];
		if (!style)
		{	var color = size>25 ? "248, 128, 0" : size>8 ? "248, 192, 0" : "128, 192, 64";
			var radius = Math.max(8, Math.min(size*0.75, 20));
			style = styleCache[size] =
				[ new ol.style.Style(
					{	image: new ol.style.Circle(
						{	radius: radius+2,
							stroke: new ol.style.Stroke(
							{	color: "rgba("+color+",0.3)", 
								width: 4
							})
						})
					}),
					new ol.style.Style(
					{	image: new ol.style.Circle(
						{	radius: radius,
							fill: new ol.style.Fill(
							{	color:"rgba("+color+",0.6)"
							})
						}),
						text: new ol.style.Text(
						{	text: size.toString(),
							fill: new ol.style.Fill(
							{	color: '#000'
							})
						})
					})
				];
		}
		return style;
	}

	// Cluster Source
	var clusterSource=new ol.source.Cluster({
		distance: 40,
		source: new ol.source.Vector()
	});
	// Animated cluster layer
	var clusterLayer = new ol.layer.AnimatedCluster(
	{	name: 'Cluster',
		source: clusterSource,
		style: getStyle
	});
	map.addLayer(clusterLayer);
	// Add 2000 features
	var ext = map.getView().calculateExtent(map.getSize());
	var features=[];
	for (var i=0; i<2000; ++i)
	{	features[i]=new ol.Feature(new ol.geom.Point([ext[0]+(ext[2]-ext[0])*Math.random(), ext[1]+(ext[3]-ext[1])*Math.random()]));
		features[i].set('id',i);
	}
	clusterSource.getSource().clear();
	clusterSource.getSource().addFeatures(features);

	// Add over interaction that draw hull in a layer
	var vector = new ol.layer.Vector({ source: new ol.source.Vector() })
	vector.setMap(map);
	
	var hover = new ol.interaction.Hover({ cursor: "pointer", layerFilter: function(l){ return l===clusterLayer; } });
	map.addInteraction(hover);
	hover.on("enter", function(e) 
		{	var h = e.feature.get("convexHull");
			if (!h)
			{	var cluster = e.feature.get("features");
				// calculate convex hull
				if (cluster && cluster.length)
				{	var c = [];
					for (var i=0, f; f = cluster[i]; i++) 
					{	c.push(f.getGeometry().getCoordinates());
					}
					h = ol.coordinate.convexHull(c);
					e.feature.get("convexHull", h);
				}
			}
			vector.getSource().clear();
			if (h.length>2) vector.getSource().addFeature ( new ol.Feature( new ol.geom.Polygon([h]) ) );
		});
	hover.on("leave", function(e) 
		{	vector.getSource().clear();
		});

	</script>
	
</body>
</html>